<template>
    <el-dialog v-model="isOpen" title="层次聚类分析结果" :border="true" :width="1000" align-center>
        <el-descriptions column="3" border>
            <el-descriptions-item label="聚类数量">{{ props.originalData.k }}</el-descriptions-item>
            <el-descriptions-item label="距离度量">{{ formatDistanceMetric(props.originalData.distanceMetric) }}</el-descriptions-item>
            <el-descriptions-item label="使用阈值">{{ props.originalData.useThreshold ? "是" : "否" }}</el-descriptions-item>
            <el-descriptions-item label="距离阈值">{{ props.originalData.distanceThreshold || "-" }}</el-descriptions-item>
            <el-descriptions-item label="特征维度" :span="2">
                <template #default>
                    {{ featureNames.join("、") }}
                </template>
            </el-descriptions-item>
            <el-descriptions-item label="计算时间" span="3">{{ result.computeTime }}ms</el-descriptions-item>
        </el-descriptions>

        <el-divider />

        <el-collapse>
            <el-collapse-item title="聚类合并步骤" name="mergeSteps">
                <el-table :data="result.mergeSteps" border style="width: 100%">
                    <el-table-column prop="cluster1Id" label="簇1 ID" align="center" width="120" />
                    <el-table-column prop="cluster2Id" label="簇2 ID" align="center" width="120" />
                    <el-table-column
                        prop="distance"
                        label="距离"
                        align="center">
                        <template #default="scope">{{ scope.row.distance.toFixed(4) }}</template>
                    </el-table-column>
                </el-table>
            </el-collapse-item>
            <el-collapse-item title="最终聚类结果" name="finalClusters">
                <el-table :data="formattedClusters" border style="width: 100%">
                    <el-table-column prop="clusterId" label="簇ID" align="center" width="100" />
                    <el-table-column prop="pointCount" label="数据点数量" align="center" width="120" />
                    <el-table-column prop="representative" label="代表性样本" align="center" width="180">
                        <template #default="scope">{{ scope.row.representative }}</template>
                    </el-table-column>
                    <el-table-column prop="pointDetails" label="包含样本" align="left">
                        <template #default="scope">
                            <el-tag
                                v-for="(item, idx) in scope.row.pointDetails"
                                :key="idx"
                                size="small"
                                style="margin: 2px"
                            >
                                {{ item }}
                            </el-tag>
                        </template>
                    </el-table-column>
                </el-table>
            </el-collapse-item>
        </el-collapse>

        <el-divider />

        <div ref="chartContainer" style="width: 100%;height: 500px" />

        <template #footer>
            <div class="dialog-footer">
                <el-button type="primary" @click="isOpen = false">关闭</el-button>
            </div>
        </template>
    </el-dialog>
</template>

<script setup>
import { computed, nextTick, ref, watch } from "vue"
import * as echarts                       from "echarts"

let isOpen = defineModel()
let props  = defineProps([ "originalData", "result" ])

let chartContainer = ref(null)
let chartInstance  = ref(null)

// 提取特征名称（从listColumn中）
const featureNames = computed(() => {
    if(!props.originalData?.listColumn){
        return [ "特征1", "特征2" ]
    }
    return props.originalData.listColumn.map(item => item.key)
})

// 获取指定索引的原始数据项
const getOriginalItem = (index) => {
    if(!props.originalData?.listAll || !props.originalData.listAll[index]){
        return { "序号": "未知", "手机型号": "未知" }
    }
    return props.originalData.listAll[index]
}

// 格式化聚类数据用于表格展示
const formattedClusters = computed(() => {
    if(!props.result || !props.result.finalClusters){
        return []
    }

    return props.result.finalClusters.map(cluster => {
        // 获取聚类中的代表性样本（第一个）
        const firstIndex     = cluster.pointIndices[0] || -1
        const representative = firstIndex !== -1
            ? getOriginalItem(firstIndex)["手机型号"]
            : "无"

        // 生成包含的样本详情（手机型号列表）
        const pointDetails = cluster.pointIndices.map(idx => {
            const item = getOriginalItem(idx)
            return `${ item["序号"] }.${ item["手机型号"] }`
        })

        return {
            clusterId : cluster.clusterId,
            pointCount: cluster.pointIndices.length,
            representative,
            pointDetails,
        }
    })
})

watch(isOpen, (val) => {
    if(val){
        initChart()
    }
    else{
        // 清理图表实例
        if(chartInstance.value){
            chartInstance.value.dispose()
            chartInstance.value = null
        }
        window.onresize = null
    }
})

function initChart(){
    nextTick(() => {
        if(!chartContainer.value || !props.result || !props.originalData?.listAll){
            return
        }

        // 确保有足够的特征维度
        const features = featureNames.value
        if(features.length < 2){
            console.error("至少需要2个特征维度用于可视化")
            return
        }

        // 准备可视化数据（使用前两个特征维度）
        const data = props.originalData.listAll.map((item, index) => {
            // 将特征值转换为数字
            return [
                Number(item[features[0]] || 0),  // X轴：第一个特征
                Number(item[features[1]] || 0),   // Y轴：第二个特征
            ]
        })

        if(!chartInstance.value){
            chartInstance.value = echarts.init(chartContainer.value)
        }

        // 创建聚类颜色映射
        const clusterColors = [
            "#3498db", "#e74c3c", "#2ecc71", "#f39c12", "#9b59b6",
            "#1abc9c", "#e67e22", "#34495e", "#95a5a6", "#27ae60",
        ]

        // 构建点到聚类的映射
        const pointToCluster = {}
        props.result.finalClusters.forEach((cluster, clusterIndex) => {
            cluster.pointIndices.forEach(pointIndex => {
                pointToCluster[pointIndex] = {
                    clusterId: cluster.clusterId,
                    color    : clusterColors[clusterIndex % clusterColors.length],
                }
            })
        })

        // 准备散点图数据（包含原始信息）
        const scatterData = data.map((point, index) => {
            const clusterInfo  = pointToCluster[index] || {
                clusterId: "未分类",
                color    : "#bdc3c7",
            }
            const originalItem = getOriginalItem(index)

            return {
                value       : point,
                itemStyle   : { color: clusterInfo.color },
                symbolSize  : 15,
                clusterId   : clusterInfo.clusterId,
                originalItem: originalItem,  // 携带原始数据用于tooltip
            }
        })

        const option = {
            tooltip: {
                trigger  : "item",
                padding  : 10,
                formatter: (params) => {
                    const original = params.data.originalItem
                    let html       = `<strong>${ original["手机型号"] }</strong><br/>`
                    // 显示所有特征信息
                    features.forEach(feature => {
                        html += `${ feature }: ${ original[feature] }<br/>`
                    })
                    html += `簇ID: ${ params.data.clusterId }`
                    return html
                },
            },
            legend : {
                data        : props.result.finalClusters.map((cluster, index) => ({
                    name     : `簇 ${ cluster.clusterId } (${ cluster.pointIndices.length }个样本)`,
                    icon     : "circle",
                    textStyle: { color: clusterColors[index % clusterColors.length] },
                })),
                bottom      : 10,
                left        : "center",
                type        : "scroll",
                pageIconSize: 12,
            },
            grid   : {
                left        : "8%",
                right       : "5%",
                bottom      : "20%",  // 增加底部空间容纳图例
                top         : "5%",
                containLabel: true,
            },
            xAxis  : {
                type        : "value",
                name        : features[0],  // 使用第一个特征名称
                nameLocation: "middle",
                nameGap     : 30,
                axisLabel   : {
                    formatter: val => val.toFixed(1),
                },
            },
            yAxis  : {
                type        : "value",
                name        : features[1],  // 使用第二个特征名称
                nameLocation: "middle",
                nameGap     : 50,
                axisLabel   : {
                    formatter: val => val.toFixed(1),
                },
            },
            series : [
                {
                    type    : "scatter",
                    name    : "聚类结果",
                    data    : scatterData,
                    emphasis: {
                        focus    : "item",
                        itemStyle: {
                            shadowBlur : 10,
                            shadowColor: "rgba(0, 0, 0, 0.5)",
                        },
                    },
                },
            ],
        }

        chartInstance.value.setOption(option)

        // 处理窗口大小变化
        const handleResize = () => {
            if(chartInstance.value){
                chartInstance.value.resize()
            }
        }
        window.addEventListener("resize", handleResize)

        // 组件关闭时移除事件监听
        const cleanup = () => {
            window.removeEventListener("resize", handleResize)
        }
        watch(isOpen, (val) => {
            if(!val){
                cleanup()
            }
        }, { once: true })
    })
}

// 格式化距离度量名称
function formatDistanceMetric(metric){
    const metrics = {
        "euclidean": "欧氏距离",
        "manhattan": "曼哈顿距离",
        "chebyshev": "切比雪夫距离",
        "minkowski": "明可夫斯基距离",
    }
    return metrics[metric] || metric
}
</script>

<style lang="scss" scoped>
::v-deep .el-collapse-item__content {
    padding: 10px 0;
}

::v-deep .el-descriptions__cell {
    padding: 12px 10px;
}

::v-deep .el-legend-scroll {
    max-width: 90%;
}
</style>

